package com.aspire.nm.component.miniServer.handle;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.aspire.nm.component.commonUtil.Reflect.ReflectUtil;
import com.aspire.nm.component.commonUtil.constants.ConstantConfig;
import com.aspire.nm.component.commonUtil.file.FileUtil;
import com.aspire.nm.component.commonUtil.random.RandomUtil;
import com.aspire.nm.component.miniServer.Controll;
import com.aspire.nm.component.miniServer.Filter;
import com.aspire.nm.component.miniServer.Server;
import com.aspire.nm.component.miniServer.annotation.Controller;
import com.aspire.nm.component.miniServer.annotation.Controller.MethodType;
import com.aspire.nm.component.miniServer.annotation.cls.Controllers;
import com.aspire.nm.component.miniServer.annotation.exception.AnnotationException;
import com.aspire.nm.component.miniServer.annotation.filter.FilterRequest;
import com.aspire.nm.component.miniServer.annotation.filter.FilterResponse;
import com.aspire.nm.component.miniServer.annotation.method.ClientIp;
import com.aspire.nm.component.miniServer.annotation.method.Header;
import com.aspire.nm.component.miniServer.annotation.method.JSessionId;
import com.aspire.nm.component.miniServer.annotation.method.Path;
import com.aspire.nm.component.miniServer.annotation.method.Req;
import com.aspire.nm.component.miniServer.annotation.method.ServerConfig;
import com.aspire.nm.component.miniServer.annotation.method.Session;
import com.aspire.nm.component.miniServer.config.DefaultDefine;
import com.aspire.nm.component.miniServer.handle.exception.ForbiddenSourceFilterException;
import com.aspire.nm.component.miniServer.handle.exception.IpFilterException;
import com.aspire.nm.component.miniServer.handle.exception.JsonFormatErrException;
import com.aspire.nm.component.miniServer.handle.exception.NotFountException;
import com.aspire.nm.component.miniServer.protocol.Http11Process;
import com.aspire.nm.component.miniServer.protocol.Request;
import com.aspire.nm.component.miniServer.protocol.Response;
import com.aspire.nm.component.miniServer.protocol.exception.SocketUnavailableException;
import com.aspire.nm.component.miniServer.render.RenderException;
import com.aspire.nm.component.miniServer.status.RoutingMethodKey;



public class HandlerThread implements Runnable{

    
    




    private List<Controll> controllImpls;
    
    private Controll routingControllImpl;
    private Method routingMehtod;
    private String routingMethodKey;
    private Object [] routingMethodParameters;
    
    private List<Filter> filterImpls;
    private List<FilterImplMethod> routingFilterRequestControllImplsMethod;
    private List<FilterImplMethod> routingFilterResponseControllImplsMethod;
    
    
    private Server server;
    private Http11Process http11Process;
    private long t;
    
    public HandlerThread(Socket socket,Server server){
        this.server = server;
        this.http11Process = new Http11Process(server,socket);
        this.t = System.currentTimeMillis();
    }
    
    
    public void run() {
        
        try{
            http11Process.initSocket();
        }catch(IOException e){
            e.printStackTrace();
            return;
        }catch(SocketUnavailableException e1){
            http11Process.close();
            server.statusInfo.clientCloseWhenExcute();
            return;
        }
        
        try{
            controllImpls = server.config.getControllImpls(false);
            filterImpls = server.config.getFilterImpls(false);
            
            Thread.currentThread().setName(RandomUtil.randStr(8));
            
            while(true){
                if(!coreProcess()){
                    break;
                }
            }
        }catch(Throwable t){
            t.printStackTrace();
        }finally{
            http11Process.close();
        }
    }
    
    
    private boolean coreProcess(){
        try {
            Request request = http11Process.getReqest();

            long t = System.currentTimeMillis();
            Response response = coreProcess(request);
            long last = System.currentTimeMillis() - t;
            
            server.statusInfo.process(request,response,last,routingMethodKey);
            
            http11Process.setResponse(response,request);
            
            return true;
            
        }catch(SocketTimeoutException e){
            //超时,服务器正常断链
            server.statusInfo.timeoutClose();
            return false;
        }catch (IOException e) {
            //客户端断链，客户端正常断链
            server.statusInfo.clientClose();
            return false;
        }
    }
    
    
    
    
    private Response coreProcess(Request request){
        
        Response response = null;
        try{
            if(request.getPath() == null || request.getPath().equals("")){
                //欢迎页
                if(!StringUtils.isEmpty(server.config.getAdminAllowIpsPattern()) && !Pattern.compile(server.config.getAdminAllowIpsPattern()).matcher(Http11Process.clientIp.get()).matches()){
                    //欢迎页  IP403
                    throw new IpFilterException();
                }else{
                    return getWelComeResp(request);
                }
            }
            
            if(request.getExtName() != null){
                if(!StringUtils.isEmpty(server.config.getForbiddenSourcePattern()) && Pattern.compile(server.config.getForbiddenSourcePattern()).matcher(request.getPath()).matches()){
                    //静态资源403
                    throw new ForbiddenSourceFilterException();
                }
                if(StringUtils.isEmpty(server.config.getAbsoluteWebappDir())){
                    //静态资源404
                    throw new NotFountException();
                }
                return getStaticResourceResp(request);
            }else{
                routingMethod(request);
                
                
                String allowIpsPattern = null;
                Object allowIpsPatternObject = server.config.getAnnotationConfig().get(routingControllImpl.getClass().getName(), "allowIpsPattern");
                if(allowIpsPatternObject != null){
                    allowIpsPattern = (String)allowIpsPatternObject;
                }
                
                if(!StringUtils.isEmpty(allowIpsPattern) && !Pattern.compile(allowIpsPattern).matcher(Http11Process.clientIp.get()).matches()){
                    //ip403
                    throw new IpFilterException();
                }
                
                routingFilterMethod(request);
                Response filterRequestResponse = invokefilterRequestMethod(request);
                if(filterRequestResponse != null){
                    response = filterRequestResponse;
                }else{
                    inject(request);
                    response = invokeMethodWithCacheTime();
                    
                    Response filterResponseResponse = invokefilterResponseMethod(response);
                    if(filterResponseResponse != null){
                        response = filterResponseResponse;
                    }
                }
                
                return response;
            }
        }catch(Throwable t){
            if(t instanceof ForbiddenSourceFilterException){
                try {response = get401Resp(request);} catch (Exception e) {e.printStackTrace();}
            }else if(t instanceof IpFilterException){
                try {response = get403Resp(Http11Process.clientIp.get());} catch (Exception e) {e.printStackTrace();}
            }else if(t instanceof NotFountException){
                try {response = get404Resp(request);} catch (Exception e) {e.printStackTrace();}
            }else if(t instanceof TimeoutException){
                try {response = get504Resp();} catch (Exception e) {e.printStackTrace();}
            }else if(t instanceof JsonFormatErrException){
                try {response = getJsonFormatErrResp();} catch (Exception e) {e.printStackTrace();}
            }else{
                t.printStackTrace();
                try {response = get500Resp(t);} catch (Exception e) {e.printStackTrace();}
            }
        }
        return response;
    }
    
    
    
    
    
    
    private String getResponseCacheKey() throws AnnotationException, InvocationTargetException, IllegalAccessException{
        Method[] methods = routingControllImpl.getClass().getDeclaredMethods();
        for(Method method:methods){
            if(method.getModifiers() == Modifier.PUBLIC &&
                    method.getName().equals(routingMehtod.getName()+"_OFKEY") && 
                    method.getReturnType().equals(String.class)){
                try {
                    if(routingMethodParameters == null){
                        return (String)method.invoke(routingControllImpl);
                    }else{
                        return  (String)method.invoke(routingControllImpl,routingMethodParameters);
                    }
                } catch (IllegalArgumentException e) {
                    throw new AnnotationException("cache key method(end with _OFKEY) parameters must same as invoke method");
                }
            }
        }
        return "";
    }
    
    
    
    
    private Response getRespFromInvokeResult(Object obj) throws NotFountException,RenderException{
        
        
        Response response = new Response();
        response.setHttpRespStatus(200);
        response.setHttpRespInfo("OK");
        response.setContentType("text/plain;charset="+server.config.getServerEncode());
        if(obj == null){
            response.setContentBytes(" ".getBytes());
            return response;
        }else{
            String returnTypePrimitiveContent = ReflectUtil.getReturnTypePrimitiveContent(routingMehtod,obj);
            if(returnTypePrimitiveContent != null){
                response.setContentBytes(returnTypePrimitiveContent.getBytes());
                return response;
            }else if(routingMehtod.getReturnType().equals(ViewModel.class)){
                
                ViewModel easyViewModel = (ViewModel)obj;
                Map<?,?> modelMap = easyViewModel.getModelMap();
                String viewTempLate = easyViewModel.getViewTemplate();
                if(StringUtils.isEmpty(server.config.getAbsoluteWebappDir())){
                   throw new NotFountException(); 
                }
                String renderResult = server.config.getCustomRender().render(modelMap, server.config.getAbsoluteWebappDir()+"/" + viewTempLate, server.config.getServerEncode());
                
                response.setContentBytes(renderResult.getBytes());
                response.setContentType("text/html;charset="+server.config.getServerEncode());
                return response;
            }else if(routingMehtod.getReturnType().equals(java.io.File.class)){
                File file = (File)obj;
                String path = file.getPath();
                if(server.getPlugins().getResourceCacher().get(path) == null){
                    synchronized(this){
                        if(server.getPlugins().getResourceCacher().get(path) == null){
                            byte[] staticContentBytes = null;
                            try {
                                staticContentBytes = FileUtil.getBytesFromFile(file);
                            } catch (IOException e) {
                                throw new NotFountException();
                            }
                            server.getPlugins().getResourceCacher().put(path, staticContentBytes,server.config.getResourceExpireSec() * 1000);
                        }
                    }
                }
                response.setContentType("application/octet-stream;");
                response.setContentBytes(server.getPlugins().getResourceCacher().get(path));
                response.setContentDisposition("attachment;filename="+file.getName());
                return response;
            }else if(routingMehtod.getReturnType().equals(Redirect.class)){
                Redirect redirect = (Redirect)obj;
                response.setHttpRespStatus(302);
                response.setHttpRespInfo("Moved Temporarily");
                response.setContentType(null);
                response.setLocation(redirect.getUrl());
                return response;
            }else{
                /**
                 * public static final Object parse(String text); // 把JSON文本parse为JSONObject或者JSONArray 
public static final JSONObject parseObject(String text)； // 把JSON文本parse成JSONObject    
public static final  T parseObject(String text, Class clazz); // 把JSON文本parse为JavaBean 
public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray 
public static final  List parseArray(String text, Class clazz); //把JSON文本parse成JavaBean集合 
public static final String toJSONString(Object object); // 将JavaBean序列化为JSON文本 
public static final String toJSONString(Object object, boolean prettyFormat); // 将JavaBean序列化为带格式的JSON文本 
public static final Object toJSON(Object javaObject); 将JavaBean转换为JSONObject或者JSONArray。
                 */
                response.setContentBytes(JSON.toJSONString(obj, false).getBytes());
                return response;
            }
        }
    }
    
    private Object invokeMethod() throws InvocationTargetException, IllegalArgumentException, IllegalAccessException  {
        if(routingMehtod.getReturnType().equals(java.lang.Void.TYPE)){
            if(routingMethodParameters == null){
                routingMehtod.invoke(routingControllImpl);
            }else{
                try{
                    routingMehtod.invoke(routingControllImpl,routingMethodParameters);
                }catch(IllegalArgumentException e){
                    String arg = "";
                    for(Object obj : routingMethodParameters){
                        arg += obj + " , ";
                    }
                    throw new RuntimeException(e + " method = " + routingMehtod.getName() + " args = " + arg);
                }
            }
            return null;
        }else{
            if(routingMethodParameters == null){
                return routingMehtod.invoke(routingControllImpl);
            }else{
                try{
                    return routingMehtod.invoke(routingControllImpl,routingMethodParameters);
                }catch(IllegalArgumentException e){
                    String arg = "";
                    for(Object obj : routingMethodParameters){
                        arg += obj+ " , ";;
                    }
                    throw new RuntimeException(e + " method = " + routingMehtod.getName() + " args = " + arg);
                }
                
            }
        }
    }
    private Object invokeMethodWithTimeOut() throws TimeoutException,AnnotationException, ExecutionException, InvocationTargetException, IllegalArgumentException, IllegalAccessException{
        Controller annotation = routingMehtod.getAnnotation(Controller.class);
        
        int timeOut = annotation.timeOut();
        if(timeOut == 0){
            Object timeOutObj = server.config.getAnnotationConfig().get(routingControllImpl.getClass().getName(), "timeOut");
            if(timeOutObj != null){
                timeOut = (Integer)timeOutObj;
            }
        }
        if(timeOut == 0){
            try{
                if(server.getPlugins().getAround() != null){
                    server.getPlugins().getAround().before(routingControllImpl,routingMehtod, routingMethodParameters);
                }
            }catch(Throwable t){
                t.printStackTrace();
            }
            Object invokeMethodResult =  invokeMethod();
            try{
                if(server.getPlugins().getAround() != null){
                    server.getPlugins().getAround().after(routingControllImpl,routingMehtod, routingMethodParameters,invokeMethodResult);
                }
            }catch(Throwable t){
                t.printStackTrace();
            }
            return invokeMethodResult;
        }
        if(t != 0){
            if(timeOut <= System.currentTimeMillis() - t){
                throw new TimeoutException();
            }else{
                timeOut = timeOut - (int)(System.currentTimeMillis() - t);
            }
            t = 0;
        }
        final String threadName = Thread.currentThread().getName();
        ExecutorService executor = Executors.newSingleThreadExecutor();
        FutureTask<Object> future = (FutureTask<Object>) executor.submit(
                 new Callable<Object>() {
                        public Object call() throws IllegalAccessException, InvocationTargetException {
                            Thread.currentThread().setName(threadName);
                            try{
                                if(server.getPlugins().getAround() != null){
                                    server.getPlugins().getAround().before(routingControllImpl,routingMehtod, routingMethodParameters);
                                }
                            }catch(Throwable t){
                                t.printStackTrace();
                            }
                            Object invokeMethodResult = invokeMethod();
                            try{
                                if(server.getPlugins().getAround() != null){
                                    server.getPlugins().getAround().after(routingControllImpl,routingMehtod, routingMethodParameters,invokeMethodResult);
                                }
                            }catch(Throwable t){
                                t.printStackTrace();
                            }
                            return invokeMethodResult;
                        }
                    }
        );
        try {
            return future.get(timeOut, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            future.cancel(true);
            executor.shutdown();
        }
        return null;
    }
    
    
    private void routingFilterMethod(Request request) {
        routingFilterRequestControllImplsMethod = new ArrayList<FilterImplMethod>();
        routingFilterResponseControllImplsMethod = new ArrayList<FilterImplMethod>();
        for(Filter filterImpl : filterImpls){
            Method[] methods = filterImpl.getClass().getDeclaredMethods();
            for(Method method:methods){
                if (method.isAnnotationPresent(FilterRequest.class)) {
                    FilterRequest annotation = method.getAnnotation(FilterRequest.class);
                    String pathParrten = annotation.pathPattern(); 
                    if(pathParrten.equals("")){
                        pathParrten = method.getName();
                    }
                    if(Pattern.compile(pathParrten, Pattern.CASE_INSENSITIVE).matcher(request.getPath()).matches()){
                        routingFilterRequestControllImplsMethod.add(new FilterImplMethod(filterImpl,method));
                    }
                }
                if (method.isAnnotationPresent(FilterResponse.class)) {
                    FilterResponse annotation = method.getAnnotation(FilterResponse.class);
                    String pathParrten = annotation.pathPattern(); 
                    if(pathParrten.equals("")){
                        pathParrten = method.getName();
                    }
                    if(Pattern.compile(pathParrten, Pattern.CASE_INSENSITIVE).matcher(request.getPath()).matches()){
                        routingFilterResponseControllImplsMethod.add(new FilterImplMethod(filterImpl,method));
                    }
                }
            }
        }
    }
    
    private void routingMethod(Request request) throws NotFountException{
        for(Controll controllImpl : controllImpls){
            String prefixPath = (String)server.config.getAnnotationConfig().get(controllImpl.getClass().getName(), "path");
            Method[] methods = controllImpl.getClass().getDeclaredMethods();
            for(Method method:methods){
                if (method.isAnnotationPresent(Controller.class)) {
                    Controller annotation = method.getAnnotation(Controller.class);
                    String pathParrten = annotation.pathPattern(); 
                    if(pathParrten.equals("")){
                        pathParrten = method.getName();
                    }
                    pathParrten = (prefixPath==null?"":prefixPath) + pathParrten;
                    
                    String methodType = ((Controllers.MethodType)server.config.getAnnotationConfig().get(controllImpl.getClass().getName(), "methodType")).toString();
                    MethodType methodType_m = annotation.methodType();
                    if(methodType_m != MethodType.FOLLOW){
                        methodType = methodType_m.toString();
                    }
                    if(methodType == MethodType.GET.toString() && !request.isGet() ||
                            methodType == MethodType.POST.toString() && request.isGet()){
                        continue;
                    }
                    if(!Pattern.compile(pathParrten, Pattern.CASE_INSENSITIVE).matcher(request.getPath()).matches()){
                        continue;
                    }
                    routingControllImpl = controllImpl;
                    routingMehtod = method;
                    routingMethodKey = RoutingMethodKey.getMethodInfo(method, false);
                    return;
                }
            }
        }
        throw new NotFountException();
    }
    
    private void inject(Request request) throws AnnotationException, JsonFormatErrException{
        routingMethodParameters = new Object[routingMehtod.getParameterTypes().length];
        
        Class<?> [] parameterTypes = routingMehtod.getParameterTypes();
        Annotation[][] annotations = routingMehtod.getParameterAnnotations();
        
        for(int i = 0;i < routingMethodParameters.length ;i ++){
            Class<?> parameterType = parameterTypes[i];
            Annotation annotation = annotations[i][0];
            if(annotation instanceof ClientIp){
                if(parameterType.equals(java.lang.String.class)){
                    routingMethodParameters[i] = Http11Process.clientIp.get();
                }else{
                    throw new AnnotationException("ClientIp Annotation must be java.lang.String");
                }
            }
            if(annotation instanceof ServerConfig){
                if(parameterType.equals(java.lang.String.class)){
                    try{
                        routingMethodParameters[i] = server.config.get(((ServerConfig) annotation).key());
                    }catch(Exception e){
                        throw new AnnotationException("ServerConfig Key can not be" + ((ServerConfig) annotation).key());
                    }
                }else{
                    throw new AnnotationException("ServerConfig Annotation must be java.lang.String");
                }
            }
            if(annotation instanceof Header){
                if(parameterType.equals(java.lang.String.class)){
                    String key = ((Header)annotation).key();
                    routingMethodParameters[i] = request.getHeaders().get(key);
                }else{
                    throw new AnnotationException("Header Annotation must be java.lang.String");
                }
            }
            if(annotation instanceof Session){
                if(parameterType.equals(java.util.Map.class)){
                    routingMethodParameters[i] = request.getSession();
                }else{
                    throw new AnnotationException("Session Annotation must be java.util.Map");
                }
            }
            if(annotation instanceof JSessionId){
                if(parameterType.equals(java.lang.String.class)){
                    routingMethodParameters[i] = request.getJsessionid();
                }else{
                    throw new AnnotationException("JSessionId Annotation must be java.util.String");
                }
            }
            if(annotation instanceof Path){
                int groupIndex = ((Path)annotation).groupIndex();
                String pathParrten = routingMehtod.getAnnotation(Controller.class).pathPattern(); 
                
                Pattern p = Pattern.compile(pathParrten, Pattern.CASE_INSENSITIVE);
                Matcher m = p.matcher(request.getPath());

                if(m.find() && m.groupCount() >= groupIndex) {
                    if(parameterType.equals(java.lang.String.class)){
                        routingMethodParameters[i] = m.group(groupIndex);
                    }else if(parameterType.equals(java.lang.Integer.class) || parameterType.equals(java.lang.Integer.TYPE)){
                        routingMethodParameters[i] = Integer.parseInt(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Byte.class) || parameterType.equals(java.lang.Byte.TYPE)){
                        routingMethodParameters[i] = Byte.parseByte(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Long.class) || parameterType.equals(java.lang.Long.TYPE)){
                        routingMethodParameters[i] = Long.parseLong(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Double.class) || parameterType.equals(java.lang.Double.TYPE)){
                        routingMethodParameters[i] = Double.parseDouble(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Float.class) || parameterType.equals(java.lang.Float.TYPE)){
                        routingMethodParameters[i] = Float.parseFloat(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Short.class) || parameterType.equals(java.lang.Short.TYPE)){
                        routingMethodParameters[i] = Short.parseShort(m.group(groupIndex));
                    }else if(parameterType.equals(java.lang.Boolean.class) || parameterType.equals(java.lang.Boolean.TYPE)){
                        if(m.group(groupIndex).toLowerCase().equals("true") || m.group(groupIndex).toLowerCase().equals("1")){
                            routingMethodParameters[i] = true;
                        }else{
                            routingMethodParameters[i] = false;
                        }
                    }else if(parameterType.equals(java.lang.Character.class) || parameterType.equals(java.lang.Character.TYPE)){
                        routingMethodParameters[i] = m.group(groupIndex).charAt(0);
                    }else{
                        throw new AnnotationException("Path Annotation Type err");
                    }
                }
            }
            if(annotation instanceof Req) {
                String key = ((Req)annotation).key();
                if(key.equals("")){
                    //post
                    if(parameterType.equals(java.lang.String.class)){
                        routingMethodParameters[i] = request.getPostdate();
                    }else if(parameterType.isArray()){
                        routingMethodParameters[i] = request.getPostdateBytes();
                    }else{
                        try{
                            routingMethodParameters[i] = JSON.parseObject(request.getPostdate(), parameterType);
                        }catch(Exception e){
                            if(!StringUtils.isEmpty(server.config.getJsonFormatErr())){
                                throw new JsonFormatErrException();
                            }else{
                                //不抛异常,不赋值
                            }
                        };
                    }
                }else{
                    //get
                    String param = request.getParams().get(key);
                    if(param != null){
                        if(parameterType.equals(java.lang.String.class)){
                            routingMethodParameters[i] = param;
                        }else if(parameterType.equals(java.lang.Integer.class) || parameterType.equals(java.lang.Integer.TYPE)){
                            try{
                                routingMethodParameters[i] = Integer.parseInt(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Byte.class) || parameterType.equals(java.lang.Byte.TYPE)){
                            try{
                                routingMethodParameters[i] = Byte.parseByte(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Long.class) || parameterType.equals(java.lang.Long.TYPE)){
                            try{
                                routingMethodParameters[i] = Long.parseLong(param);
                            }catch(Exception e){}    
                        }else if(parameterType.equals(java.lang.Double.class) || parameterType.equals(java.lang.Double.TYPE)){
                            try{
                                routingMethodParameters[i] = Double.parseDouble(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Float.class) || parameterType.equals(java.lang.Float.TYPE)){
                            try{
                                routingMethodParameters[i] = Float.parseFloat(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Short.class) || parameterType.equals(java.lang.Short.TYPE)){
                            try{
                                routingMethodParameters[i] = Short.parseShort(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Boolean.class) || parameterType.equals(java.lang.Boolean.TYPE)){
                            try{
                                routingMethodParameters[i] = Boolean.parseBoolean(param);
                            }catch(Exception e){}
                        }else if(parameterType.equals(java.lang.Character.class) || parameterType.equals(java.lang.Character.TYPE)){
                            try{
                                routingMethodParameters[i] = param.charAt(0);
                            }catch(Exception e){}
                        }else{
                            throw new AnnotationException("Req Annotation with key = " + key + "Type err");
                        }
                    }
                }
            }
        }
        
    }
    
    
    
   
    private Response invokefilterResponseMethod(Response response) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, NotFountException, RenderException{
        
        for(int i = routingFilterResponseControllImplsMethod.size() - 1;i>=0;i--){
            FilterImplMethod filterImplMethod = routingFilterResponseControllImplsMethod.get(i);
            Filter filter = filterImplMethod.filter;
            Method method = filterImplMethod.method;
            Object obj = null;
            if(method.getReturnType().equals(java.lang.Void.TYPE)){
                method.invoke(filter,response);
            }else{
                obj = method.invoke(filter, response);
            }
            if(obj != null){
                return getRespFromInvokeResult(obj);
            }
        }
        return null;
    }
    private Response invokefilterRequestMethod(Request request) throws NotFountException,  IllegalArgumentException, IllegalAccessException, InvocationTargetException, RenderException{
        for(FilterImplMethod filterImplMethod : routingFilterRequestControllImplsMethod){
            Filter filter = filterImplMethod.filter;
            Method method = filterImplMethod.method;
            Object obj = null;
            if(method.getReturnType().equals(java.lang.Void.TYPE)){
                method.invoke(filter,request);
            }else{
                obj = method.invoke(filter, request);
            }
            if(obj != null){
                return getRespFromInvokeResult(obj);
            }
        }
        return null;
    }
    
    private Response invokeMethodWithCacheTime() throws AnnotationException, TimeoutException, NotFountException, InvocationTargetException, ExecutionException, IllegalArgumentException, IllegalAccessException, RenderException{
        Response response = null;
        Controller annotation = routingMehtod.getAnnotation(Controller.class);
        int cacheTime = annotation.cacheTime();
        if(cacheTime != 0){
            String key = routingControllImpl.getClass().getName()+"_"+routingMehtod.getName() + "_" + getResponseCacheKey();
            response = (Response)server.getPlugins().getIfCacher().get(key);
            if(response == null){
                response = getRespFromInvokeResult(invokeMethodWithTimeOut());
                response.setIfcacherExpireTime(System.currentTimeMillis() + cacheTime);
            	server.getPlugins().getIfCacher().put(key, response, cacheTime);
            }
        }else{
            Object obj =invokeMethodWithTimeOut();
            response = getRespFromInvokeResult(obj);
        }
        return response;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    /*
      
     
    private void inject(Request request) throws IllegalArgumentException, IllegalAccessException{
        Field[] fields = routingControllImpl.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            Annotation[] AnnotationFileds = field.getAnnotations();
            for(Annotation annotation : AnnotationFileds) {
                if(annotation instanceof ServerPort){
                    field.set(routingControllImpl, request.getServerPort());
                }
                if(annotation instanceof ClientIp){
                    field.set(routingControllImpl, request.getInetAddress().toString().substring(1));
                }
                if(annotation instanceof Header){
                    String key = ((Header)annotation).key();
                    if(request.getHeaders().get(key) != null){
                        field.set(routingControllImpl, request.getHeaders().get(key));
                    }
                }
                if(annotation instanceof Req) {
                    String key = ((Req)annotation).key();
                    if(key.equals("")){
                        //post
                        if(field.getType().equals(java.lang.String.class)){
                            field.set(routingControllImpl, request.getPostdate());
                        }else{
                            try{
                                field.set(routingControllImpl, JSON.parseObject(request.getPostdate(), field.getType()));
                            }catch(Exception e){
                                field.set(routingControllImpl,null);
                            };
                        }
                    }else{
                        //get
                        if(field.getType().equals(java.lang.Integer.class) || field.getType().equals(java.lang.Integer.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Integer.parseInt(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Byte.class) || field.getType().equals(java.lang.Byte.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Byte.parseByte(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Long.class) || field.getType().equals(java.lang.Long.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Long.parseLong(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Double.class) || field.getType().equals(java.lang.Double.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Double.parseDouble(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Float.class) || field.getType().equals(java.lang.Float.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Float.parseFloat(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Short.class) || field.getType().equals(java.lang.Short.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Short.parseShort(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Boolean.class) || field.getType().equals(java.lang.Boolean.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, Boolean.parseBoolean(request.getParams().get(key)));
                            }
                        }else if(field.getType().equals(java.lang.Character.class) || field.getType().equals(java.lang.Character.TYPE)){
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, request.getParams().get(key).charAt(0));
                            }
                        }else{
                            if(request.getParams().get(key) != null){
                                field.set(routingControllImpl, request.getParams().get(key));
                            }
                        }
                    }
                }
                if(annotation instanceof Path){
                    int groupIndex = ((Path)annotation).groupIndex();
                    Controller toBeInvokeMethodAnnotation = routingMehtod.getAnnotation(Controller.class);
                    String pathParrten = toBeInvokeMethodAnnotation.pathPattern(); 
                    
                    Pattern p = Pattern.compile(pathParrten, Pattern.CASE_INSENSITIVE);
                    Matcher m = p.matcher(request.getPath());

                    if(m.find() && m.groupCount() >= groupIndex) {
                        try {
                            
                            if(field.getType().equals(java.lang.Integer.class) || field.getType().equals(java.lang.Integer.TYPE)){
                                field.set(routingControllImpl, Integer.parseInt(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Byte.class) || field.getType().equals(java.lang.Byte.TYPE)){
                                field.set(routingControllImpl, Byte.parseByte(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Long.class) || field.getType().equals(java.lang.Long.TYPE)){
                                field.set(routingControllImpl, Long.parseLong(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Double.class) || field.getType().equals(java.lang.Double.TYPE)){
                                field.set(routingControllImpl, Double.parseDouble(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Float.class) || field.getType().equals(java.lang.Float.TYPE)){
                                field.set(routingControllImpl, Float.parseFloat(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Short.class) || field.getType().equals(java.lang.Short.TYPE)){
                                field.set(routingControllImpl, Short.parseShort(m.group(groupIndex)));
                            }else if(field.getType().equals(java.lang.Boolean.class) || field.getType().equals(java.lang.Boolean.TYPE)){
                                if(m.group(groupIndex).toLowerCase().equals("true") || m.group(groupIndex).toLowerCase().equals("1")){
                                    field.set(routingControllImpl, true);
                                }else{
                                    field.set(routingControllImpl, false);
                                }
                            }else if(field.getType().equals(java.lang.Character.class) || field.getType().equals(java.lang.Character.TYPE)){
                                field.set(routingControllImpl, m.group(groupIndex).charAt(0));
                            }else{
                                field.set(routingControllImpl, m.group(groupIndex));
                            }
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace(System.out);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace(System.out);
                        }
                    }
                }
            }
        }
    }
    
    */
 
    
    
    
    
    
    
    
    
    
    
    private Response get401Resp(Request request){

        Map<String,String> model  = new HashMap<String,String>();
        model.put("path", request.getPath());
        
        String forbiddenTemplateContent;
        try {
            forbiddenTemplateContent = server.config.getNativeRender().render(model, "template/forbidden.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
            
        Response response = new Response();
        response.setHttpRespStatus(401);
        response.setHttpRespInfo("Forbidden");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(forbiddenTemplateContent.getBytes());
        return response;
    }
    
    private Response getStaticResourceResp(Request request) throws NotFountException {
        String path  = server.config.getAbsoluteWebappDir()+"/" + request.getPath();
        
        if(server.getPlugins().getResourceCacher().get(path) == null){
            synchronized(this){
                if(server.getPlugins().getResourceCacher().get(path) == null){
                    File file = new File(path);
                    if(!file.exists()){
                        throw new NotFountException();
                    }
                    byte[] staticContentBytes = null;
                    try {
                        staticContentBytes = FileUtil.getBytesFromFile(file);
                    } catch (IOException e) {
                        throw new NotFountException();
                    }
                    server.getPlugins().getResourceCacher().put(path, staticContentBytes,server.config.getResourceExpireSec() * 1000);
                }
            }
        }
        byte[] staticContentBytes = server.getPlugins().getResourceCacher().get(path);
        String contentType = ConstantConfig.getPropertiesValue("config/properties/mimeType.properties", request.getExtName());
        Response response = new Response();
        response.setHttpRespStatus(200);
        response.setHttpRespInfo("OK");
        response.setContentBytes(staticContentBytes);
        if(contentType != null){
            response.setContentType(contentType+";charset="+server.config.getServerEncode());
        }else{
            response.setContentType("application/octet-stream;");
        }
        return response;
    }
    
    
    private Response get403Resp(String ip) {
        
        Map<String,String> model  = new HashMap<String,String>();
        model.put("ip", ip);
        String ipFilterTemplateContent;
        try {
            ipFilterTemplateContent = server.config.getNativeRender().render(model, "template/ipfilter.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(403);
        response.setHttpRespInfo("Forbidden");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(ipFilterTemplateContent.getBytes());
        
        return response;
    }
    private Response get404Resp(Request request){
        
        Map<String,String> model  = new HashMap<String,String>();
        model.put("path", request.getPath());
        model.put("req", request.getParamString());
        model.put("isGet", String.valueOf(request.isGet()));
        model.put("postdate", request.getPostdate());
        model.put("contentLengh", String.valueOf(request.getContentLength()));
        
        String unfoundTemplateContent;
        try {
            unfoundTemplateContent = server.config.getNativeRender().render(model, "template/unfound.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(404);
        response.setHttpRespInfo("Not Fount");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(unfoundTemplateContent.getBytes());
        
        return response;
    }
    
    private Response get504Resp() {
        
        Map<String,String> model  = new HashMap<String,String>();
        String timeoutTemplateContent;
        try {
            timeoutTemplateContent = server.config.getNativeRender().render(model, "template/timeout.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(504);
        response.setHttpRespInfo("Gateway Timeout");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(timeoutTemplateContent.getBytes());
        
        return response;
    }
    
    private Response get500Resp(Throwable t){
        
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        t.printStackTrace(pw);
        String errMessage =  "<br/>" + sw.toString().replaceAll("\r\n", "<br/>") + "<br/>";
        
        Map<String,String> model  = new HashMap<String,String>();
        model.put("errMessage", errMessage);
        String errorTemplateContent;
        try {
            errorTemplateContent = server.config.getNativeRender().render(model, "template/error.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(500);
        response.setHttpRespInfo("Server Internal Error");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(errorTemplateContent.getBytes());
        
        return response;
    }
    private Response getJsonFormatErrResp(){
        
        Response response = new Response();
        response.setHttpRespStatus(200);
        response.setHttpRespInfo("OK");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(server.config.getJsonFormatErr().getBytes());
        
        return response;
    }
    
    private String showClassName(String className){
        String result = "";
        String [] tmps = className.split("\\.");
        int index = 0;
        for(String tmp : tmps){
            result += tmp+".";
            index ++;
            if(index%3==0){
                result += "<br/>";
            }
        }
        if(result.endsWith(".")){
            result = result.substring(0,result.length() - 1);
        }
        return result;
    }
    
    private Response getWelComeResp(Request request){
        
        Map<String,Object> model  = new HashMap<String,Object>();
        model.put("statusInfo", server.statusInfo);
        
        model.put("serverPort_dft", DefaultDefine.getDefault("serverPort"));
        model.put("corePoolSize_dft", DefaultDefine.getDefault("corePoolSize"));
        model.put("maximumPoolSize_dft", DefaultDefine.getDefault("maximumPoolSize"));
        model.put("workQueueSize_dft", DefaultDefine.getDefault("workQueueSize"));
        model.put("sessionExpireSec_dft", DefaultDefine.getDefault("sessionExpireSec"));
        model.put("resourceExpireSec_dft", DefaultDefine.getDefault("resourceExpireSec"));
        model.put("absoluteWebappDir_dft", DefaultDefine.getDefault("absoluteWebappDir"));
        model.put("forbiddenSourcePattern_dft", DefaultDefine.getDefault("forbiddenSourcePattern"));
        model.put("allowIpsPattern_dft", DefaultDefine.getDefault("allowIpsPattern"));
        model.put("adminAllowIpsPattern_dft", DefaultDefine.getDefault("adminAllowIpsPattern"));
        model.put("serverEncode_dft", DefaultDefine.getDefault("serverEncode"));
        model.put("clientEncode_dft", DefaultDefine.getDefault("clientEncode"));
        model.put("renderFactoryClassName_dft", showClassName(DefaultDefine.getDefault("renderFactoryClassName")));
        model.put("jsonFormatErr_dft", DefaultDefine.getDefault("jsonFormatErr"));
        model.put("annotationValueConfigFile_dft", DefaultDefine.getDefault("annotationValueConfigFile"));
        model.put("accessLogInLine_dft", DefaultDefine.getDefault("accessLogInLine"));
        
        model.put("serverPort", String.valueOf(server.config.getServerPort()));
        
        model.put("corePoolSize", server.config.getCorePoolSize());
        model.put("maximumPoolSize", server.config.getMaximumPoolSize());
        model.put("workQueueSize", server.config.getWorkQueueSize());
        
        model.put("sessionExpireSec", server.config.getSessionExpireSec());
        model.put("resourceExpireSec", server.config.getResourceExpireSec());
        
        model.put("absoluteWebappDir", server.config.getAbsoluteWebappDir());
        
        model.put("forbiddenSourcePattern", server.config.getForbiddenSourcePattern());
        model.put("allowIpsPattern", server.config.getAllowIpsPattern());
        model.put("adminAllowIpsPattern", server.config.getAdminAllowIpsPattern());
        
        model.put("serverEncode", server.config.getServerEncode());
        model.put("clientEncode", server.config.getClientEncode());
        
        model.put("renderFactoryClassName", showClassName(server.config.getRenderFactoryClassName()));
        
        model.put("jsonFormatErr", server.config.getJsonFormatErr());
        
        model.put("annotationValueConfigFile", server.config.getAnnotationValueConfigFile());
        model.put("accessLogInLine", server.config.getAccessLogInLine());
        
        String welcomeTemplateContent;
        try {
            welcomeTemplateContent = server.config.getNativeRender().render(model, "template/welcome.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(200);
        response.setHttpRespInfo("OK");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(welcomeTemplateContent.getBytes());
        return response;
    }
    private Response get503Resp(){
        Map<String,String> model  = new HashMap<String,String>();
        String unavailableTemplateContent;
        try {
            unavailableTemplateContent = server.config.getNativeRender().render(model, "template/unavailable.template", server.config.getServerEncode());
        } catch (RenderException e) {
            e.printStackTrace();
            return null;
        }
        
        Response response = new Response();
        response.setHttpRespStatus(503);
        response.setHttpRespInfo("Service Unavailable");
        response.setContentType("text/html;charset="+server.config.getServerEncode());
        response.setContentBytes(unavailableTemplateContent.getBytes());
        
        return response;
    }
    
    
    
    
    
    
    
    public void resp503(){
        Response response = get503Resp();
        try {
            http11Process.initSocket();
            http11Process.setResponse(response,null);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        } catch (IOException e2) {
            e2.printStackTrace();
        } catch (SocketUnavailableException e2) {
            e2.printStackTrace();
        }finally {
            http11Process.close();
        }
    }
    
}



final class FilterImplMethod{
    public FilterImplMethod(Filter filter,Method method){
        this.filter = filter;
        this.method = method;
    }
    public Filter filter;
    public Method method;
}